<template>
    <form @submit.prevent="handleSubmit">
        <slot></slot>
    </form>
</template>

<script lang="ts" setup>
import { onMounted, reactive,provide } from 'vue';

// 定义规则类型
export type RuleItem = {
    trigger: "Input" | 'Change' | 'Blur',
    type: "Required" | 'Numbric',
    errorMsg: string,
    name: string,
};

// 定义组件属性
const props = defineProps<{
    rules: RuleItem[];
    modelValue?: Record<string, any>;
}>();

// 定义事件
const emit = defineEmits<{
    'update:modelValue': [value: Record<string, any>];
    'submit': [formData: Record<string, any>, isValid: boolean];
}>();

// 存储表单内的所有Input组件引用
const inputComponents = reactive<Map<string, any>>(new Map());

// 存储校验状态
const validationStatus = reactive<Record<string, {
    valid: boolean;
    errorMsg: string;
}>>({});

// 注册子组件
const registerInput = (name: string, component: any) => {
    inputComponents.set(name, component);
};

// 处理子组件的校验结果
const handleValidation = (name: string, isValid: boolean, errorMsg: string) => {
    validationStatus[name] = { valid: isValid, errorMsg };
};

// 校验整个表单
const validateForm = (): boolean => {
    let isValid = true;
    
    // 对每个注册的Input组件进行校验
    inputComponents.forEach((component, name) => {
        // 找到该输入框对应的规则
        const inputRules = props.rules.filter(rule => rule.name === name);
        
        // 找出所有需要的触发器
        const triggers = new Set<string>();
        inputRules.forEach(rule => triggers.add(rule.trigger));
        
        // 对每个触发器执行校验
        triggers.forEach(trigger => {
            const result = component.validate(trigger);
            if (!result) isValid = false;
        });
    });
    
    return isValid;
};

// 处理表单提交
const handleSubmit = () => {
    const isValid = validateForm();
    emit('submit', props.modelValue || {}, isValid);
};

// 暴露方法给父组件
defineExpose({
    validate: validateForm,
    registerInput,
    handleValidation
});

// 提供给子组件使用的方法和状态
provide('formContext', {
    registerInput,
    handleValidation,
    rules: props.rules
});

onMounted(() => {
    // 组件挂载后可以执行一些初始化操作
});
</script>

<style scoped>
.error-msg {
    color: #f56c6c;
    font-size: 12px;
    line-height: 1;
    padding-top: 4px;
}
</style>